package com.tool4j.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.tool4j.entity.TableMetadata;
import com.tool4j.entity.TemplateFile;
import com.tool4j.entity.TemplateInfo;
import com.tool4j.entity.params.JavaCodeConfig;
import com.tool4j.entity.vo.FileResult;
import com.tool4j.service.TemplateFileService;
import com.tool4j.service.TemplateInfoService;
import com.tool4j.util.velocity.VelocityConfig;
import com.tool4j.util.velocity.VelocityParserPlus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class GenerateCodeUtil {

    @Autowired
    private TemplateInfoService templateInfoService;

    @Autowired
    private TemplateFileService templateFileService;

    public List<FileResult> generate(List<TableMetadata> metadataList, JavaCodeConfig config) {
        List<FileResult> results = new ArrayList<>();
        TemplateInfo templateInfo;
        if (StrUtil.isBlank(config.getTemplateId())) {
            templateInfo = templateInfoService.findDefault(config.getOrmType());
        } else {
            templateInfo = templateInfoService.findById(Long.parseLong(config.getTemplateId()));
        }
        List<TemplateFile> templateFiles = templateFileService.findFilesByTemplateId(templateInfo.getId());
        Assert.notNull(templateInfo, "模板不存在");
        List<VelocityConfig> list = covertConfig(metadataList, config);
        list.forEach(velocityConfig -> {
            for (TemplateFile fileInfo : templateFiles) {
                velocityConfig.setTemplate(String.format("%s/%s/%s", templateInfo.getPath(), fileInfo.getFilePath(), fileInfo.getFileName()));
                String fileName;
                if (StrUtil.isNotBlank(fileInfo.getFilePath())) {
                    String filePath = fileInfo.getFilePath().replace("package", config.getBasePackage());
                    fileName = String.format("%s/%s",
                            filePath.replace(".", "/"),
                            fileInfo.getFileName().replace(".vm", "").replace("_className_", velocityConfig.getUpperClassName())
                    );
                } else {
                    fileName = String.format("%s/%s",
                            config.getBasePackage().replace(".", "/"),
                            fileInfo.getFileName()
                                    .replace(".vm", "")
                                    .replace("_className_", velocityConfig.getUpperClassName())
                    );
                }
                if (results.stream().anyMatch(item -> item.getFileName().equalsIgnoreCase(fileName))) {
                    return;
                }
                String content;
                try {
                    content = VelocityParserPlus.execute(velocityConfig);
                } catch (Exception e) {
                    content = "模板渲染失败\n\n" + e;
                }
                int index = fileName.lastIndexOf(".");
                String fileType = index != -1 ? fileName.substring(index + 1) : "java";
                results.add(new FileResult(fileName.replace("/package/", "/"), fileType, content));
            }
        });
        return results;
    }

    /**
     * 解析为Velocity配置类
     *
     * @param config
     * @return
     */
    private List<VelocityConfig> covertConfig(List<TableMetadata> metadataList, JavaCodeConfig config) {
        return metadataList.stream().map(item -> {
            String upperClassName = item.getUpperClassName();
            String lowClassName = item.getLowClassName();
            String tableNamePrefix = config.getTableNamePrefix();
            if (tableNamePrefix.endsWith("_")) {
                tableNamePrefix = tableNamePrefix.substring(0, tableNamePrefix.length() - 1);
            }
            //裁剪表名前缀
            if (StrUtil.isNotBlank(tableNamePrefix)) {
                if (upperClassName.toUpperCase().startsWith(tableNamePrefix.toUpperCase())) {
                    upperClassName = upperClassName.substring(tableNamePrefix.length());
                    //裁切后若首字母是“_”，则删除
                    if (upperClassName.startsWith("_")) {
                        upperClassName = upperClassName.substring(1);
                    }
                    //裁切后首字母可能是大写，需转为小写
                    lowClassName = VelocityParserPlus.getLowerName(lowClassName.substring(tableNamePrefix.length()));
                }
            }
            String apiPrefix = "/api/";
            if (StrUtil.isNotBlank(config.getApiPathPrefix())) {
                apiPrefix = config.getApiPathPrefix();
                if (!apiPrefix.startsWith("/")) {
                    apiPrefix = "/" + apiPrefix;
                }
                if (!apiPrefix.endsWith("/")) {
                    apiPrefix = apiPrefix + "/";
                }
            }

            VelocityConfig velocityConfig = new VelocityConfig()
                    .setAuthor(config.getAuthor())
                    .setSince(DateUtil.now())
                    .setPackagePath(config.getBasePackage())
                    .setComment(StrUtil.isBlank(item.getComment()) ? " " : item.getComment())
                    .setUpperClassName(upperClassName)
                    .setLowClassName(lowClassName)
                    .setTableName(item.getTableName())
                    .setApiPath(apiPrefix + lowClassName)
                    .setColumns(item.getColumnMetadataList());
            // 方法配置
            velocityConfig.setMethods(config.getMethodConfigMap());
            velocityConfig.setNeedLombok(config.isUseLombok())
                    .setNeedSwagger(config.isSwaggerSupport())
                    .setUseClassComment(config.isUseClassComment())
                    .setUseMethodComment(config.isUseMethodComment())
                    .setUseFieldComment(config.isUseFieldComment());
            return velocityConfig;
        }).collect(Collectors.toList());
    }
}
